import logging
import hashlib
import os
from fastapi import APIRouter, File, UploadFile, HTTPException, Depends, Request
from app.utils.request_utils import get_user_params  # 导入全局方法
from app.utils.response_utils import build_response
from app.controllers.upload_controller import apply_file_upload_lease
from app.models.new_upload_model import upload_file

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

new_upload_router = APIRouter()

# 允许的文件类型
ALLOWED_FILE_TYPES = {"pdf", 'docx'}
# 最大文件大小（这里设置为 100MB）
MAX_FILE_SIZE = 100 * 1024 * 1024

# 定义文件保存的目录
UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)

async def validate_file(file: UploadFile = File(...)):
    file_ext = file.filename.split(".")[-1].lower()
    if file_ext not in ALLOWED_FILE_TYPES:
        logger.error(f"不允许的文件类型: {file_ext}")
        raise HTTPException(status_code=400, detail=f"不允许的文件类型，仅支持 {', '.join(ALLOWED_FILE_TYPES)}")
    content = await file.read()
    file.file.seek(0)
    if len(content) > MAX_FILE_SIZE:
        logger.error(f"文件大小超过限制: {len(content)} 字节")
        raise HTTPException(status_code=400, detail=f"文件大小不能超过 {MAX_FILE_SIZE / (1024 * 1024)} MB")
    return file

async def calculate_file_md5(file: UploadFile):
    hash_object = hashlib.sha256()  # 使用更安全的SHA256算法
    for chunk in iter(lambda: file.file.read(4096), b""):
        hash_object.update(chunk)
    file.file.seek(0)  # 重置文件指针
    return hash_object.hexdigest()

async def save_file_to_server(file: UploadFile):
    """
    将文件保存到服务器本地目录
    :param file: 上传的文件对象
    :return: 保存后的文件路径
    """
    file_path = os.path.join(UPLOAD_DIR, file.filename)
    try:
        with open(file_path, "wb") as buffer:
            buffer.write(await file.read())
        logger.info(f"文件成功保存到服务器，文件路径: {file_path}")
        return file_path
    except Exception as e:
        logger.error(f"保存文件到服务器时出错: {e}")
        return None

@new_upload_router.post("/upload/")
async def upload(
    request: Request,
    file: UploadFile = File(...)
):
    params = await get_user_params(request)
    category_id = params.get("category_id")

    if not category_id:
        logger.error("CategoryId 为空")
        return build_response(100, '分类不能为空')

    try:
        validated_file = await validate_file(file)
        size_in_bytes = len(await validated_file.read())  # 获取文件大小
        validated_file.file.seek(0)  # 重置文件指针
        md5 = await calculate_file_md5(validated_file)  # 获取文件 MD5 值
        file_name = file.filename  # 获取文件名称

        logger.info(f"开始上传文件，CategoryId: {category_id}，文件大小: {size_in_bytes} 字节，MD5: {md5}，文件名: {file_name}")

        file_path = await save_file_to_server(validated_file)
        if file_path:
            # 获取文件的绝对路径
            absolute_file_path = os.path.abspath(file_path)
            logger.info(f"文件上传成功，CategoryId: {category_id}")
            # 在返回结果中添加文件大小、MD5 值和文件名以及保存路径和绝对路径
            result = {
                "file_size": size_in_bytes,
                "file_md5": md5,
                "file_name": file_name,
                "file_path": file_path,
                "absolute_file_path": absolute_file_path
            }
            #调用上传文件函数
            if hasattr(apply_file_upload_lease, "__await__"):
                lease_result = await apply_file_upload_lease(category_id, file_name, size_in_bytes, md5)
            else:
                lease_result = apply_file_upload_lease(category_id, file_name, size_in_bytes, md5)
            if "error" in lease_result:
                return build_response(100, '失败', '名字已存在')
            print(lease_result)
            # 从返回结果中获取 body 部分
            body = lease_result.get("body")
            if body is None:
                return build_response(100, '失败', "返回结果有误")

            # 从 body 中获取 Data 部分
            data = body.get("Data")
            if data is None:
                return build_response(100, '失败', "返回结果有误")

            FileUploadLeaseId = data.get("FileUploadLeaseId")
            print(f"获取到的 FileUploadLeaseId: {FileUploadLeaseId}")

            if not FileUploadLeaseId:
                return build_response(100, '失败', "返回结果有误")
            # 从 body 中获取 Param 部分
            param = data.get("Param")
            if param is None:
                return build_response(100, '失败', "返回结果有误")

            headers = param.get("Headers")
            if headers is None:
                return build_response(100, '失败', "返回结果有误")
            print(f"获取到的 headers: {headers}")
            extra = headers.get("X-bailian-extra")
            print(f"获取到的 extra: {extra}")
            if not extra:
                return build_response(100, '失败', "返回结果有误")
            content_type = headers.get("Content-Type")
            if not content_type:
                return build_response(100, '失败', "返回结果有误")
            pre_signed_url = param.get("Url")
            if not pre_signed_url:
                return build_response(100, '失败', "返回结果有误")
            res=upload_file(pre_signed_url,file,extra,content_type)
            return build_response(200, '成功', res)
        else:
            return build_response(100, "文件保存到服务器失败，请稍后重试", {})

    except FileNotFoundError as e:
        logger.error(f"文件未找到，CategoryId: {category_id}, 错误信息: {str(e)}")
        return build_response(100, "文件未找到", {"error_detail": str(e)})
    except PermissionError as e:
        logger.error(f"没有权限访问文件，CategoryId: {category_id}, 错误信息: {str(e)}")
        return build_response(100, "没有权限访问文件", {"error_detail": str(e)})
    except Exception as e:
        logger.error(f"文件上传过程中出现未知错误，CategoryId: {category_id}, 错误信息: {e}")
        return build_response(100, "文件上传过程中出现未知错误，请稍后重试", {"error_detail": str(e)})